import datetime
import json
import re
import copy
import pandas as pd
import Core.Gadget as Gadget
import os


class Quote(object):

    def __init__(self, database, realtime):
        self.cached_quotes = {}
        self.database = database
        self.realtime = realtime
        self.cache_format = "Symbol_Key"  # "Symbol_Key" , "Daily_Key", "Monthly_Key"
        self.max_back_days_to_find = 10
        self.quote_usage_count = pd.DataFrame(columns=["Symbol", "Count", "Update_Time"])
        self.max_cache_length = 1000
        self.print_debug_info = False

    def Get_Quote(self, symbol, update_date):
        # 从数据库读出的数据，进行字段适配
        quote = self.Find_Quote(symbol, update_date)
        if quote:
            if "close" in quote:
                quote["Close"] = quote["close"]
            if "adjusted_net_asset_value" in quote:
                quote["Close"] = quote["adjusted_net_asset_value"]
            if "adjusted_nav" in quote:
                quote["Close"] = quote["adjusted_nav"]
            #
            if "adjfactor" in quote:
                quote["AdjFactor"] = quote["adjfactor"]
            else:
                quote["AdjFactor"] = 1
        return quote

    def Find_Quote(self, symbol, update_date):
        # ---统计用量---
        # ---该表用来记录数据被调用的次数，之后清除数据时，从使用比较少开始清理---
        datetime_now = datetime.datetime.now()
        if symbol not in self.quote_usage_count.index:
            self.quote_usage_count.loc[symbol] = [symbol, 0, datetime.datetime(2020,9,17)]
        else:
            self.quote_usage_count.loc[symbol, "Count"] += 1

        # 是否需要重载，距离上次重载数据超过24小时
        reload = False
        last_update_time = self.quote_usage_count.loc[symbol, "Update_Time"]
        lag_days = (datetime_now - last_update_time).days
        if lag_days >= 1:
            reload = True

        # ---先从内存中读取---
        # 若无需重载，说明是最新数据
        if not reload and symbol in self.cached_quotes.keys():
            df_bars = self.cached_quotes.get(symbol)
            quote = self.Find_Suitable_Time_Bar(df_bars, update_date)
            if quote:
                # print("Data in Memory", symbol, update_date)
                return quote

        # --- 判断是否需要清除部分内存---
        self.Check_Max_Cache_Size()

        # ---尝试从Realtime读取数据---
        if self.realtime != None:
            quote = self.Get_Quote_from_Realtime(symbol, update_date)
            if quote == None:  # 如果找不到当天，尝试找几天前的数据
                for i in range(1, self.max_back_days_to_find):
                    back_date = update_date + datetime.timedelta(days=-1 * i)
                    quote = self.Get_Quote_from_Realtime(symbol, back_date)
                    if quote:
                        break
            if quote:
                # print("Data in RealTime", symbol, update_date)
                return quote

        # --- 尝试从数据库读取数据---
        quote = self.Get_Quote_from_Database(symbol, update_date)
        if quote:
            # print("Data in Database", symbol, update_date)
            return quote

        # ---无论如何也找不到的情况---
        return None

    def Check_Max_Cache_Size(self):
        if len(self.cached_quotes) >= self.max_cache_length:
            numToRelease = int(0.1 * self.max_cache_length)
            #
            self.quote_usage_count.sort_values(by=["Count"], ascending=True, inplace=True)
            #
            i = 0
            for index, row in self.quote_usage_count.iterrows():
                symbol = row["Symbol"]
                if symbol in self.cached_quotes:
                    print("Quote: Try to delete cache " + row["Symbol"] + " Count " + str(row["Count"]))
                    del self.cached_quotes[symbol]
                    i += 1
                if i >= numToRelease:
                    break

    def Find_Suitable_Time_Bar(self, df_bars, update_date):
        #
        df_bars_selected = df_bars[df_bars["date"] <= update_date]
        if len(df_bars_selected) == 0:
            df_result = df_bars.iloc[-1:]  # 没有合适时间，返回全集的最后一个
        else:
            df_result = df_bars_selected.iloc[-1:]  # 有合适区间返回
        #
        quote = df_result.to_dict(orient='records')
        return quote[0]

    def Get_Quote_from_Database(self, symbol, update_date):
        #
        instrument_types = ["Stock", "Index", "Future", "MutualFund", "Option"]
        for instrument_type in instrument_types:
            # documents = self.database.Get_Daily_Bar(symbol, instrumentType=instrument_type)
            df_bars = self.database.Get_Daily_Bar_DataFrame(symbol, instrument_type=instrument_type)
            if len(df_bars) > 0:
                break

        # ---Symbol 完全没有数据---
        if len(df_bars) == 0:
            print("Quote Error, no data in database", symbol)
            return None

        # ---加入缓存---
        self.cached_quotes[symbol] = df_bars
        self.quote_usage_count.loc[symbol, "Update_Time"] = datetime.datetime.now()

        # ---Symbol 有数据，但是没有适合的时间区间---
        quote = self.Find_Suitable_Time_Bar(df_bars, update_date)
        return quote

    def Get_Quote_from_Realtime(self, symbol, update_date):
        quote = None
        # "Symbol_Key" , "Daily_Key", "Monthly_Key"
        if self.cache_format == "Symbol_Key":
            #
            key = symbol + "_" + Gadget.ToDateString(update_date)
            quote = self.realtime.GetHashDocument(symbol, key)

        elif self.cache_format == "Monthly_Key":
            #
            year_month = update_date.year * 100 + update_date.month
            monthly_key = symbol + "_" + str(year_month)
            monthly_document_data = self.realtime.GetManyHashDocuments(monthly_key)
            # if len(monthly_document_data) > 0:
            #     document_list = list(monthly_document_data.values())
            #     for documant in document_list:
            #         tmp_date = documant["date"]
            #         self.cached_quotes[symbol][tmp_date] = documant

        elif self.cache_format == "Daily_Key":
            pass

        #
        return quote


def TestQuote(database, realtime):
    #
    instruments = database.Get_Instruments_DataFrame(instrument_type="Stock")
    instruments = instruments[0:20]
    symbol_lit = instruments["symbol"].tolist()

    update_date = datetime.datetime(2020, 9, 6)
    quote = Quote(database, realtime)
    count = 0
    for symbol in symbol_lit:
        count += 1
        if count == 11:
            a = 0
        print(symbol, count)
        q = quote.Get_Quote(symbol, update_date)
        q = quote.Get_Quote(symbol, update_date)
        print(q["date"], q["close"])


if __name__ == '__main__':

    from Core.Config import *
    pathfilename = os.getcwd() + "\..\Config\config_develop.json"
    config = Config(pathfilename)
    database = config.DataBase("JDMySQL")
    realtime = config.RealTime(db=0)
    #
    TestQuote(database, realtime)